﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using TracyGUI.UIComponent;
using Tracy;
using Tracy.DataModel;
using System.Xml;
using System.IO;
using ICSharpCode.SharpZipLib.Zip;
using SharedLib.Helpers;

namespace TracyGUI
{
    public partial class FormMain
    {
        private void ZipXml(XmlDocument doc, string fileName)
        {
            ZipOutputStream s = new ZipOutputStream(new FileStream(fileName, FileMode.Create));
            try
            {
                s.SetLevel(9);
                ZipEntry ze = new ZipEntry("ExportedEntries.xml");
                ze.DateTime = DateTime.Now;
                s.PutNextEntry(ze);
                doc.Save(s);
                s.Finish();
            }
            finally
            {
                s.Close();
            }
        }

        private XmlDocument UnzipXml(string fileName)
        {
            if (File.Exists(fileName))
            {
                XmlDocument doc = new XmlDocument();
                ZipInputStream s = new ZipInputStream(File.OpenRead(fileName));
                try
                {
                    ZipEntry ze = s.GetNextEntry();
                    
                    if (ze != null)
                    {
                        if (Path.GetFileName(ze.Name) != "ExportedEntries.xml") return null;
                        doc.Load(s);
                    }
                }
                finally
                {
                    s.Close();
                }
                return doc;
            }
            return null;
        }

        private void importToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (openFileDialogMain.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                XmlDocument docToImport = UnzipXml(openFileDialogMain.FileName);
                if (docToImport != null)
                {
                    //Entries can be imported
                    FormSelection<ListBoxItemEntry> entrySelectionForm = new FormSelection<ListBoxItemEntry>("Entry Selection", "Please select the entries to be imported", true);
                    foreach (XmlElement entryNode in docToImport.SelectNodes("/entries/entry"))
                    {
                        entrySelectionForm.AddItem(new ListBoxItemEntry(new Entry(entryNode)));
                    }
                    if (entrySelectionForm.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                    {
                        List<ListBoxItemEntry> selectedItems = entrySelectionForm.GetSelectedItems();
                        if (selectedItems.Count > 0)
                        {
                            List<Entry> entriesToUpdate = new List<Entry>();
                            List<Entry> entriesToAdd = new List<Entry>();
                            foreach (ListBoxItemEntry item in selectedItems)
                            {
                                //Check whether the entries already exist or not
                                Entry entry = item.Data;
                                Entry existingEntry = TracyFacade.Instance.EntryProvider.GetItemByName(entry.Name);
                                if (existingEntry != null)
                                {
                                    entry.Properties["original-id"] = existingEntry.ID;//Set the id of the existing entry
                                    entriesToUpdate.Add(entry);
                                }
                                else
                                {
                                    entriesToAdd.Add(entry);
                                }
                            }

                            bool updateSuccess = UpdateImportingEntries(entriesToUpdate, docToImport);
                            bool addSuccess = AddImportingEntries(entriesToAdd, docToImport);
                            if (updateSuccess || addSuccess) MessageBox.Show("Import Completed.");
                        }
                    }
                    
                }
                else
                {
                    MessageBox.Show("Failed to import data");
                }
            }
            
        }

        private bool UpdateImportingEntries(List<Entry> entriesToUpdate, XmlDocument docToImport)
        {
            if (entriesToUpdate == null || entriesToUpdate.Count == 0 || docToImport == null) return false;
            
            StringBuilder sb = new StringBuilder ();
            foreach (Entry entry in entriesToUpdate)
            {
                sb.Append(entry.Name);
                sb.Append("\n");
            }

            if (MessageBox.Show("The following entries \n" + sb.ToString() + " already exist, do you want to update them?", "Importing", MessageBoxButtons.YesNo) == System.Windows.Forms.DialogResult.Yes)
            {
                DoImportingEntries(entriesToUpdate, docToImport);
                return true;
            }

            return false;
        }
        
        private bool AddImportingEntries(List<Entry> entriesToAdd, XmlDocument docToImport)
        {
            if (entriesToAdd == null || entriesToAdd.Count == 0 || docToImport == null) return false;

            MessageBox.Show("Please choose the parent folder for the new entries");
            //Select SavePath parent folder
            folderBrowserDialogMain.SelectedPath = TracyFacade.Instance.UserPreferenceManager.SavePath;
            if (folderBrowserDialogMain.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                DoImportingEntries(entriesToAdd, docToImport);
                return true;
            }
            return false;
        }

        private void DoImportingEntries(List<Entry> entriesToUpdate, XmlDocument docToImport)
        {
            foreach (Entry entry in entriesToUpdate)
            {
                //Update entry
                XmlNode entryNode = docToImport.SelectSingleNode(String.Format("/entries/entry[@id='{0}']", entry.ID));
                if (entryNode != null)
                {
                    Entry existingEntry = null;
                    dynamic removedEntryInfo = null;
                    if (entry.Properties.ContainsKey("original-id")) existingEntry = TracyFacade.Instance.EntryProvider.GetItemByID(entry.Properties["original-id"]);

                    if (existingEntry == null) //add entry
                    {
                        entry.Attributes.Remove("id"); //Generate new entry id and save path
                        entry.SavePath = folderBrowserDialogMain.SelectedPath + "\\" + StringHelper.RemoveInvalidCharFromFileName(entry.Name);
                        TracyFacade.Instance.EntryProvider.AddItem(entry);
                    }
                    else //update entry
                    {
                        entry.Attributes["id"] = existingEntry.ID; //Use original ID and save path
                        entry.SavePath = existingEntry.SavePath;
                        removedEntryInfo = BeginUpdateEntryInList(entry);
                        TracyFacade.Instance.EntryProvider.UpdateItem(entry);
                    }

                    //Update Filter Sets
                    List<FilterSet> filterSets = new List<FilterSet>();
                    List<FilterSet> existingFilterSets = null;
                    if (existingEntry != null)
                    {
                        existingFilterSets = TracyFacade.Instance.FilterManager.FilterProvider.GetFilterSets(entry);
                        filterSets.AddRange(existingFilterSets);
                    }
                    foreach (XmlNode filterSetNode in entryNode.SelectNodes("filter-sets/filterset"))
                    {
                        FilterSet fs = new FilterSet(filterSetNode);
                        bool willAdd = true;
                        if (existingFilterSets != null)
                        {
                            foreach (FilterSet existingFS in existingFilterSets) //Remove duplicated filtersets
                            {
                                if (fs.Equals(existingFS))
                                {
                                    willAdd = false;
                                    break;
                                }
                            }
                        }
                        if (willAdd) filterSets.Add(fs);
                    }
                    TracyFacade.Instance.FilterManager.FilterProvider.SetFilterSets(filterSets, entry);

                    //Update Resources
                    foreach (XmlNode resNode in entryNode.SelectNodes("resources/resource"))
                    {
                        Resource res = new Resource(resNode);
                        if (existingEntry == null || !TracyFacade.Instance.ResourceProvider.IsResourceExisting(res))
                        {
                            res.Entry = entry;
                            TracyFacade.Instance.ResourceProvider.AddItem(res);
                            _formNewResourceSelection.AddItem(new ListBoxItemResource(res));
                        }
                    }

                    //Update Tags
                    List<Tag> tags = new List<Tag>();
                    List<Tag> existingTags = null;
                    if (existingEntry != null)
                    {
                        existingTags = TracyFacade.Instance.TagManager.GetTags(entry);
                        tags.AddRange(existingTags);
                    }
                    foreach (XmlNode tagNode in entryNode.SelectNodes("tags/tag"))
                    {
                        Tag tag = new Tag(tagNode);
                        bool willAdd = true;
                        if (existingTags != null)
                        {
                            foreach (Tag existingTag in existingTags)//Remove duplicated tags
                            {
                                if (tag.Equals(existingTag))
                                {
                                    willAdd = false;
                                    break;
                                }
                            }
                        }
                        if (willAdd) tags.Add(tag);
                    }
                    TracyFacade.Instance.TagManager.SetTags(entry, tags);

                    //Update UI
                    if (removedEntryInfo != null)
                    {
                        EndUpdateEntryInList(removedEntryInfo);
                    }
                    else
                    {
                        AddEntryToList(entry);
                        _ueEntry.UpdateTreeForItemChange(entry);
                    }
                }
            }
        }

        

        private void exportToolStripMenuItem_Click(object sender, EventArgs e)
        {
            FormSelection<ListBoxItemEntry> entrySelectionForm = new FormSelection<ListBoxItemEntry>("Entry Selection", "Please select the entries to be exported", true);
            //Entries available
            foreach (Entry en in GetEntriesInList())
            {
                entrySelectionForm.AddItem(new ListBoxItemEntry(en));
            }
            
            if (entrySelectionForm.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                if (saveFileDialogMain.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    XmlDocument doc = new XmlDocument();
                    XmlElement entryLiseNode = doc.CreateElement("entries");
                    foreach (ListBoxItemEntry item in entrySelectionForm.GetSelectedItems())
                    {
                        Entry entry = item.Data;
                        //Clear save path info
                        entry.SavePath = null;

                        XmlNode entryNode = entry.ToXmlNode(doc);
                        
                        //Export Filter Set
                        XmlNode filterSetListNode = doc.CreateElement("filter-sets");
                        foreach (FilterSet filterSet in TracyFacade.Instance.FilterManager.FilterProvider.GetFilterSets(entry))
                        {
                            filterSetListNode.AppendChild(filterSet.ToXmlNode(doc));
                        }
                        entryNode.AppendChild(filterSetListNode);
                        
                        //Export Resource
                        XmlNode resourceListNode = doc.CreateElement("resources");
                        foreach (Resource res in TracyFacade.Instance.ResourceProvider.GetItemByEntry(entry))
                        {
                            if (!String.IsNullOrEmpty(res.Url))
                            {
                                res.Status = "New";
                                res.Entry = null;
                                resourceListNode.AppendChild(res.ToXmlNode(doc));
                            }
                        }
                        entryNode.AppendChild(resourceListNode);
                        
                        //Export Tags
                        XmlNode tagListNode = doc.CreateElement("tags");
                        foreach (Tag tag in TracyFacade.Instance.TagManager.GetTags(entry))
                        {
                            tagListNode.AppendChild(tag.ToXmlNode(doc));
                        }
                        entryNode.AppendChild(tagListNode);

                        entryLiseNode.AppendChild(entryNode);
                    }
                    doc.AppendChild(entryLiseNode);

                    ZipXml(doc, saveFileDialogMain.FileName);
                    MessageBox.Show("Export Completed");
                }
            }

        }

        private void importFolderToolStripMenuItem_Click(object sender, EventArgs e)
        {
            //Select folder to be imported
            if (folderBrowserDialogMain.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                //Select files to be imported
                FormSelection<UIDataWrapper<string>> fileSelection = new FormSelection<UIDataWrapper<string>>("File Selection", "Please select the files to be imported", true);
                foreach (string filePath in Directory.EnumerateFiles(folderBrowserDialogMain.SelectedPath, "*.*", SearchOption.AllDirectories))
                {
                    fileSelection.AddItem(new UIDataWrapper<string>(filePath, Path.GetFileName(filePath)));
                }

                if (fileSelection.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    FormInput inputForm = new FormInput() { Message = "Please enter the name of the entry:", Value = folderBrowserDialogMain.SelectedPath.Substring(folderBrowserDialogMain.SelectedPath.LastIndexOf("\\") + 1) };
                    if (inputForm.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                    {
                        Entry newEntry = new Entry(inputForm.Value);
                        newEntry.Name = inputForm.Value;
                        newEntry.TracingDisabled = true;
                        newEntry.SavePath = folderBrowserDialogMain.SelectedPath;
                        TracyFacade.Instance.EntryProvider.AddItem(newEntry);

                        foreach (UIDataWrapper<string> item in fileSelection.GetSelectedItems())
                        {
                            Resource res = new Resource();
                            res.Entry = newEntry;
                            res.Created = File.GetCreationTime(item.Data).ToString();
                            res.Title = item.Text;
                            res.Status = "Sent"; //TODO: use other status
                            TracyFacade.Instance.ResourceProvider.AddItem(res);

                            MediaFile file = new MediaFile();
                            file.Resource = res;
                            file.FileName = item.Text;
                            file.Status = "Watched";
                            if (MediaFile.IsVisible(item.Text))file.Visible = "true";
                            int prefixLength = folderBrowserDialogMain.SelectedPath.Length + 1;
                            file.Location = item.Data.Substring(prefixLength, item.Data.Length - prefixLength - item.Text.Length);
                            TracyFacade.Instance.MediaFileProvider.AddItem(file);
                        }

                        AddEntryToList(newEntry);
                        _ueEntry.UpdateTreeForItemChange(newEntry);
                    }
                }
            }
        }
    
    }
}